package com.hz.api.admin.web.service.Impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.file.FileWriter;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.*;
import com.baomidou.mybatisplus.annotation.OrderBy;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.hz.api.admin.common.exception.BizException;
import com.hz.api.admin.model.dao.ApiUserPicsDao;
import com.hz.api.admin.model.entity.ApiUserPicsEntity;
import com.hz.api.admin.web.config.thread.UserContextHolder;
import com.hz.api.admin.web.service.UserPicsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

@Service
@Slf4j
public class UserPicsServiceImpl implements UserPicsService {

    @Value("${upload.file-path}")
    private String uploadFilePath;

    @Value("${upload.file-prefix}")
    private String uploadFilePrefix;

    @Value("${aliyun.oss.bucket-name}")
    private String bucketName;

    @Value("${aliyun.oss.endpoint}")
    private String endpoint;

    private final Object lock = new Object();

    private final AtomicInteger atomicInteger = new AtomicInteger(0);

    public final LoadingCache<String, Object> cache = CacheBuilder.newBuilder()
            .maximumSize(1000) // 设置缓存的最大容量
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .build(new CacheLoader<String, Object>() {
                @Override
                public Integer load(String fileName) {
                    return 0;
                }
            });


    @Resource
    private ApiUserPicsDao apiUserPicsDao;


    private OSSClient ossClient;

    public void updateProgress(String fileName, Object progress) {
        cache.put(fileName, progress);
    }

    public Object getProgress(String fileName) {
        try {
            return cache.get(fileName);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void uploadPicture(MultipartFile[] files) {
        synchronized (lock) {
            MultipartFile file = files[0];
            log.info("|------上传文件信息: 文件名={}, 大小={}", file.getOriginalFilename(), file.getSize());
            try {
                // 计算当前日期
                Date date = DateUtil.date();
                int year = DateUtil.year(date);
                int month = DateUtil.month(date);
                String fileDir = UserContextHolder.getAccountInfoDTO().getLocalFilePath() + File.separator + year + File.separator + month;
                long startTime = System.currentTimeMillis();
                String fileIndex = fileDir + File.separator + file.getOriginalFilename();
                FileWriter writer = new FileWriter(fileIndex);
                writer.writeFromStream(file.getInputStream());
                ApiUserPicsEntity entity = new ApiUserPicsEntity();
                entity.setUserId(UserContextHolder.getUserId());
                entity.setCreateTime(new Date());
                entity.setModifyTime(new Date());
                entity.setFileIndex(fileIndex);
                entity.setFilePrefix(fileDir);
                entity.setUsername(UserContextHolder.getAccountInfoDTO().getUsername());
                BigDecimal bigDecimal = new BigDecimal(file.getSize()).divide(new BigDecimal(1048576), 2, RoundingMode.HALF_UP);
                entity.setFileSize(String.valueOf(bigDecimal));
                apiUserPicsDao.insert(entity);
                log.info("|______上传结束，耗时: {}ms", System.currentTimeMillis() - startTime);
            } catch (Exception e) {
                log.error("上传出现异常：{}", e);
            }
        }
    }

    @Override
    public PageInfo<ApiUserPicsEntity> getUserPics(Integer pageSize, Integer pageNum) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("user_id", UserContextHolder.getUserId());
        queryWrapper.orderByDesc("create_time");
        return PageHelper.startPage(pageNum, pageSize)
                .doSelectPageInfo(() -> apiUserPicsDao.selectList(queryWrapper));
    }

    @Override
    @Async("taskExecutor")
    public void downloadPicture(String dirPath) {
        log.info("start downloadPicture....");
        try {
            // 列举Bucket下的所有文件
            ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName);
            listObjectsRequest.setPrefix("");
            listObjectsRequest.setMaxKeys(100);
            ObjectListing objectListing;
            // 总文件数
            int totalCount = 0;
            // 已下载文件数
            int downloadedCount = 0;
            do {
                objectListing = ossClient.listObjects(listObjectsRequest);
                totalCount += objectListing.getObjectSummaries().size();
                listObjectsRequest.setMarker(objectListing.getNextMarker());
            } while (objectListing.isTruncated());

            do {
                objectListing = ossClient.listObjects(listObjectsRequest);
                for (OSSObjectSummary objectSummary : objectListing.getObjectSummaries()) {
                    downloadedCount++;
                    String key = objectSummary.getKey();
                    File localFile = new File(dirPath, key);
                    if (!localFile.getParentFile().exists()) {
                        localFile.getParentFile().mkdirs();
                    }

                    InputStream inputStream = ossClient.getObject(bucketName, key).getObjectContent();
                    Files.copy(inputStream, Paths.get(localFile.getAbsolutePath()));
                    inputStream.close();
                    // 计算并打印进度
                    BigDecimal ret =
                            new BigDecimal(downloadedCount).divide(new BigDecimal(totalCount), 2, RoundingMode.HALF_UP);
                    BigDecimal progress = ret.multiply(new BigDecimal(100));
                    updateProgress("progress", progress);
                }
                listObjectsRequest.setMarker(objectListing.getNextMarker());
            } while (objectListing.isTruncated());
            log.info("All files have been downloaded....");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public String downloadProcess() {
        String progress = getProgress("progress") == null ? "0" : String.valueOf(getProgress("progress"));
        if (atomicInteger.get() == 0 && "100.00".equals(progress)) {
            atomicInteger.incrementAndGet();
        }
        if (atomicInteger.get() == 1) {
            cache.put("progress", 0);
            atomicInteger.decrementAndGet();
        }
        return progress;
    }

    @Override
    public Long getUserPicsNum() {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("user_id", UserContextHolder.getUserId());
        queryWrapper.orderByDesc("create_time");
        return apiUserPicsDao.selectCount(queryWrapper);
    }

    @Override
    public void loadLocalPicture() {

    }


}
